metadata = read_tsv(here('data', 'metadata_merged.tsv'), col_types = cols()) %>%
  rename(TimePoint = Timepoint) %>%
  mutate(TimePoint = str_replace(TimePoint, '^', 'T'),
         condition = str_c(CornVariety, FungalStrain, TissueExtraction, sep='_')) %>%
  rename(Corn_Genotype = CornVariety, Fungal_Treatment = FungalStrain, Tissue_Extraction = TissueExtraction)
get_counts = function(.) otu_table(.) %>% as.data.frame() %>% rownames_to_column('feature_id') %>% as_tibble()
get_tax = function(.) tax_table(.) %>% data.frame() %>% rownames_to_column('feature_id') %>% as_tibble()
get_qza = function(filepath){read_qza(filepath)$data %>% as.data.frame() %>% rownames_to_column('SampleID')}
change_its_ids_to_match_16S = . %>% 
  mutate(SampleID = str_replace(SampleID, '(.*?)-(.*)', '\\2-\\1'),
         SampleID = str_replace_all(SampleID, c('-B73'='-373', '-C322'='-322')))
change_16S_ids_to_match_ITS = . %>% 
  mutate(SampleID = str_replace(SampleID, '(.*?)-(.*)', '\\2-\\1'),
         SampleID = str_replace_all(SampleID, c('-373'='-B73', '-322'='-C322')))
ps %>% imap(~get_counts(.x) %>% 
              left_join(reads_df[[.y]], by='feature_id') %>%
              left_join(get_tax(.x), by='feature_id') %>%
              rename(all_of(get_sample_data(.x) %>% pull(SampleID, name=condition_w_rep))) %>%
              write_csv(here(str_glue('output/raw_counts_and_taxonomy_{.y}.csv')))
              )
$`16S`

$ITS
NA

Removed taxa not assigned to a phylum. After removing these taxa, 1 16S samples was removed due to having total counts <= 1500.

ps_phylum_filt = list('16S' = subset_taxa(ps$`16S`, !is.na(Phylum) & 
                                            !Phylum %in% c('', 'uncharacterized', 'unidentified') & 
                                            !Kingdom %in% c('d__Eukaryota')) %>% 
                        prune_samples(sample_sums(.) >= 1500, .) %>% prune_taxa(taxa_sums(.) > 0, .),
                      'ITS' = subset_taxa(ps$ITS, !is.na(Phylum) & 
ps_phylum_filt_tax = ps_phylum_filt %>% map(get_tax)
ps_phylum_filt_counts = ps_phylum_filt %>% map(get_counts)
ps_phylum_filt_ra = map(ps_phylum_filt, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_phylum_filt
phyloseq-class experiment-level object
otu_table()   OTU Table:         [ 946 taxa and 48 samples ]
sample_data() Sample Data:       [ 48 samples by 10 sample variables ]
tax_table()   Taxonomy Table:    [ 946 taxa by 7 taxonomic ranks ]
phy_tree()    Phylogenetic Tree: [ 946 tips and 919 internal nodes ]

$ITS
phyloseq-class experiment-level objectsample_data() Sample Data:       [ 50 samples by 9 sample variables ]
reads = list('16S' = read_qza(here('data', '16S', 'rep-seqs-filtered.qza'))$data,
             'ITS' = read_qza(here('data', 'ITS', 'rep-seqs-filtered.qza'))$data)
ps_phylum_filt %>% imap(function(ps_phylum_filt, seq_type){
  ps_phylum_filt %>% get_tax() %>%
    summarize(across(-feature_id, ~sum(!is.na(.x))/ n())) %>%
    pivot_longer(everything(), names_to = 'Taxonomic rank', values_to = seq_type)
  reduce(full_join, by='Taxonomic rank') %>%
  kable_classic(full_width = F, html_font = "Times New Roman") 
Fraction of ASVs classified at each rank
Taxonomic rank 16S ITS
Kingdom 1.00 1.00
Phylum 1.00 1.00
Class 1.00 0.99
Order 1.00 0.93
Family 0.99 0.89
Genus 0.91 0.86
Species 0.28 0.73
ps_phylum_filt %>% imap(function(ps_phylum_filt, seq_type){
  ps_phylum_filt %>% sample_sums() %>% enframe(name = 'SampleID', value = 'total_counts') %>%
    left_join(metadata, by='SampleID') %>%
    mutate(seq_type = seq_type)
  ggplot(aes(x=condition, y=total_counts)) +
  geom_boxplot(outlier.shape = NA) +
  ggbeeswarm::geom_quasirandom(alpha = 0.3, width=0.2, groupOnX=TRUE) +
  facet_wrap(~seq_type, ncol=1, scales = 'free') +
  scale_y_continuous(labels = scales::comma) +
  labs(title='Total number of counts for each sample') +
  ggeasy::easy_center_title()




Rarefying to 1569 counts.

ps_phylum_filt_rarefied =  ps_phylum_filt %>% map(
  ~rarefy_even_depth(.x, sample.size = 1569, rngseed=1100 , replace=FALSE) %>%
     prune_taxa(taxa_sums(.) > 0, .))
ps_phylum_filt_rarefied
phyloseq-class experiment-level object





$ITS
phyloseq-class experiment-level object
otu_table()   OTU Table:         [ 111 taxa and 50 samples ]
sample_data() Sample Data:       [ 50 samples by 9 sample variables ]
tax_table()   Taxonomy Table:    [ 111 taxa by 7 taxonomic ranks ]phy_tree()    Phylogenetic Tree: [ 111 tips and 109 internal nodes ]







prev = map(ps_phylum_filt_ra,
            function(ps_phylum_filt_ra){
              relative_counts = ps_phylum_filt_ra %>% get_counts()
              tax = ps_phylum_filt_ra %>% get_tax()
                         prevalence = rowSums(.> 0) -1, #subtracted 1 because feature_id column is always counted
                         Phylum = tax$Phylum,
                         Genus = tax$Genus,
                         Species = tax$Species)})
prev_plots = prev %>% imap(function(prev, seq_type){
  prev %>% 
    mutate(prevalence = prevalence / nsamples(ps_phylum_filt[[seq_type]])) %>%
    geom_hline(yintercept = 0.05, alpha = 0.5, linetype = 2) + 
    geom_point(size = 2, alpha = 0.6) +
    scale_x_log10() + xlab("Total Relative Abundance") + ylab("Prevalence [Fraction Samples]") +
    facet_wrap(~Phylum) +
    labs(title = glue('{seq_type} ASV Prevalence')) +
    theme(plot.title = element_text(hjust = 0.5)) +
prev_plots$`16S` %>% plotly::ggplotly()
Warning: `gather_()` was deprecated in tidyr 1.2.0.
Please use `gather()` instead.
prev_plots$ITS %>% plotly::ggplotly()

Predominant phyla

ps_phyla = map(ps_phylum_filt, 
               function(ps_phylum_filt){
                 prevalenceThreshold =  0.05 * nsamples(ps_phyla)
                   get_counts() %>% 
                             prevalence = rowSums(.> 0),
                             TotalAbundance = taxa_sums(ps_phyla)) %>%
                   pull(feature_id) %>%
                   prune_taxa(., ps_phyla) %>%
                   prune_samples(sample_sums(.) >= 500, .) %>% 
                   as('data.frame') %>%
                   mutate(TissueType = fct_relevel(TissueType, 'Ovule'))
                 return(ps_phyla)})
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
prev_corn_phyla = map(ps_phyla_ra,
            function(ps_phyla_ra){
            relative_counts = ps_phyla_ra %>% get_counts()
              tax = ps_phyla_ra %>% get_tax()
              relative_counts %>% 
                left_join(metadata, by='SampleID') %>%
                left_join(tax, by='feature_id') %>%
                group_by(Phylum) %>%
                mutate(prevalence_entire_dataset = sum(counts > 0) / n(),
                       mean_relative_abundance_entire_dataset = mean(counts)) %>%
                group_by(Phylum, Corn_Genotype) %>%
                          mean_relative_abundance = mean(counts),
                ungroup()})
prev_corn_phyla$`16S` %>% 
  distinct(Phylum, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  arrange(desc(total)) %>%
  kbl(format = 'html', col.names = c('Phylum', 'Total Relative Abundance', 
  kable_classic(full_width = F, html_font = "Times New Roman")
Phylum Total Relative Abundance Relative abundance B73 Relative abundance CML322
Proteobacteria 0.866 0.829 0.899
Firmicutes 0.065 0.118 0.016
Actinobacteriota 0.038 0.041 0.035
Bacteroidota 0.030 0.010 0.050
prev_corn_phyla$ITS %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  #filter(total >= 0.01) %>%
  arrange(desc(total)) %>%
  kbl(format = 'html', col.names = c('Phylum', 'Total Relative Abundance', 
  kable_classic(full_width = F, html_font = "Times New Roman")
Phylum Total Relative Abundance Relative abundance B73 Relative abundance CML322
Ascomycota 0.999 0.999 0.999
Basidiomycota 0.001 0.001 0.001




Removed taxa that are present in less than 5% of samples for ASV level dataset. This will be used for differential abundance testing at ASV level.

ps_prevf = map2(ps_phylum_filt, prev,
               function(ps_phylum_filt, prev){
                 prevalenceThreshold =  0.05 * nsamples(ps_phylum_filt)
                 keepTaxa = filter(prev, prevalence >= prevalenceThreshold) %>% 
                 prune_taxa(keepTaxa, ps_phylum_filt) %>%
                   prune_samples(sample_sums(.) >= 500, .) %>% 
ps_prevf_ra = map(ps_prevf, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_prevf_clr = map(ps_prevf, microbiome::transform, 'clr')
ps_prevf_alr = map(ps_prevf, microbiome::transform, 'alr', shift=1)
ps_prevf
$`16S`

otu_table()   OTU Table:         [ 287 taxa and 48 samples ]
sample_data() Sample Data:       [ 48 samples by 10 sample variables ]
tax_table()   Taxonomy Table:    [ 287 taxa by 7 taxonomic ranks ]
phy_tree()    Phylogenetic Tree: [ 287 tips and 278 internal nodes ]

$ITS
phyloseq-class experiment-level objectotu_table()   OTU Table:         [ 51 taxa and 50 samples ]




Agglomerated counts at both genus level and species level.

ps_genus = map(ps_phylum_filt, 
                 ps_genus = tax_glom(ps_phylum_filt, "Genus", NArm = TRUE)
                 prevalenceThreshold =  0.05 * nsamples(ps_genus)
                 ps_genus = ps_genus %>% 
                   get_counts() %>% 
                   summarise(feature_id = feature_id,
                             prevalence = rowSums(.> 0),
                             TotalAbundance = taxa_sums(ps_genus)) %>%
                   filter(prevalence >= prevalenceThreshold) %>% 
                   prune_taxa(., ps_genus) %>%
                   prune_samples(sample_sums(.) >= 500, .) %>% 
                   prune_taxa(taxa_sums(.) > 0, .)
                 sample_data(ps_genus) = sample_data(ps_genus) %>% 
                   as('data.frame') %>%
                   mutate(TissueType = fct_relevel(TissueType, 'Ovule'))
                 return(ps_genus)})
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ps_genus_ra = map(ps_genus, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_genus_clr = map(ps_genus, microbiome::transform, 'clr')
ps_genus_alr = map(ps_genus, microbiome::transform, 'alr', shift=1)
ps_species = map(ps_phylum_filt, 
               function(ps_phylum_filt){
                 ps_species = ps_species %>% 
                   get_counts() %>% 
                   summarise(feature_id = feature_id,
                             TotalAbundance = taxa_sums(ps_species)) %>%
                   filter(prevalence >= prevalenceThreshold) %>% 
                   pull(feature_id) %>%
                   prune_taxa(., ps_species) %>%
                   prune_samples(sample_sums(.) >= 500, .) %>% 
                 sample_data(ps_species) = sample_data(ps_species) %>% 
                   as('data.frame') %>%
                 return(ps_species)})
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ps_species_ra = map(ps_species, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_species_clr = map(ps_species, microbiome::transform, 'clr')
ps_species_alr = map(ps_species, microbiome::transform, 'alr', shift=1)

Most prevalent genera

prev_corn_genus = map(ps_genus_ra,
            function(ps_genus_ra){
            relative_counts = ps_genus_ra %>% get_counts()
              tax = ps_genus_ra %>% get_tax()
                pivot_longer(-feature_id, names_to = 'SampleID', values_to = 'counts') %>%
                left_join(metadata, by='SampleID') %>%
                left_join(tax, by='feature_id') %>%
                group_by(Genus) %>%
                mutate(prevalence_entire_dataset = sum(counts > 0) / n(),
                summarize(prevalence = sum(counts > 0) / n(),
                          mean_relative_abundance_entire_dataset = first(mean_relative_abundance_entire_dataset)) %>%
                ungroup()})
prev_corn_genus$`16S` %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Genus, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  filter(total >= 0.01) %>%
  arrange(desc(total)) %>%
  kable_classic(full_width = F, html_font = "Times New Roman")
Genus Total Relative Abundance Relative abundance B73 Relative abundance CML322
Pantoea 0.461 0.419 0.500
Klebsiella 0.094 0.024 0.159
Enterobacter 0.051 0.101 0.005
Carnimonas 0.041 0.085 0.000
Burkholderia-Caballeronia-Paraburkholderia 0.030 0.048 0.013
Serratia 0.029 0.033 0.026
Stenotrophomonas 0.029 0.014 0.043
Lactococcus 0.024 0.048 0.003
Sphingobacterium 0.024 0.007 0.039
Achromobacter 0.023 0.008 0.036
Rosenbergiella 0.022 0.047 0.000
Listeria 0.019 0.040 0.000
Allorhizobium-Neorhizobium-Pararhizobium-Rhizobium 0.017 0.009 0.023
Ochrobactrum 0.017 0.013 0.020
Enterococcus 0.010 0.013 0.007
prev_corn_genus$ITS %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Genus, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  arrange(desc(total)) %>%
                                     'Relative abundance B73', 'Relative abundance CML322')) %>%
Genus Total Relative Abundance Relative abundance B73 Relative abundance CML322
Aspergillus 0.552 0.497 0.608
Sarocladium 0.252 0.226 0.279
Meyerozyma 0.124 0.148 0.101
Talaromyces 0.040 0.076 0.003
Trichoderma 0.013 0.026 0.001
Penicillium 0.006 0.011 0.001
Curvularia 0.005 0.007 0.003
Alternaria 0.004 0.007 0.002
Ramichloridium 0.001 0.001 0.001
Acremonium 0.000 0.001 0.000
Bipolaris 0.000 0.000 0.000
Candida 0.000 0.000 0.000
Ceriporia 0.000 0.000 0.000
Cladosporium 0.000 0.000 0.000
Cyphellophora 0.000 0.000 0.000
Exserohilum 0.000 0.000 0.000
Fomes 0.000 0.000 0.000
Fusarium 0.000 0.000 0.000
Lecanicillium 0.000 0.000 0.000
Moesziomyces 0.000 0.000 0.000
Myrothecium 0.000 0.001 0.000
Paraconiothyrium 0.000 0.000 0.000
Peniophora 0.000 0.000 0.000
Peziza 0.000 0.001 0.000
Phanerochaete 0.000 0.000 0.000
Phlebia 0.000 0.000 0.000
Pyricularia 0.000 0.000 0.000
Scopuloides 0.000 0.000 0.000
Stereum 0.000 0.001 0.000
Tinctoporellus 0.000 0.000 0.000
Trametes 0.000 0.000 0.000
unidentified 0.000 0.000 0.000

Most prevalent species

prev_corn_species = map(ps_species_ra,
            function(ps_species_ra){
                pivot_longer(-feature_id, names_to = 'SampleID', values_to = 'counts') %>%
                left_join(metadata, by='SampleID') %>%
                left_join(tax, by='feature_id') %>%
                group_by(Species) %>%
                mutate(prevalence_entire_dataset = sum(counts > 0) / n(),
                group_by(Species, Corn_Genotype) %>%
                          prevalence_entire_dataset = first(prevalence_entire_dataset),
                          mean_relative_abundance_entire_dataset = first(mean_relative_abundance_entire_dataset)) %>%
                ungroup()})
prev_corn_species$`16S` %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Species, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  arrange(desc(total)) %>%
  kable_classic(full_width = F, html_font = "Times New Roman")
Species Total Relative Abundance Relative abundance B73 Relative abundance CML322
Pantoea_ananatis 0.193 0.207 0.173
Burkholderia_gladioli 0.152 0.195 0.091
Listeria_grayi 0.070 0.119 0.000
Lactococcus_lactis 0.068 0.077 0.056
Sphingobacterium_siyangense 0.050 0.001 0.120
Lactococcus_garvieae 0.043 0.073 0.000
Sphingobacterium_thalpophilum 0.032 0.000 0.079
Sphingomonas_phyllosphaerae 0.030 0.000 0.073
Acinetobacter_baumannii 0.029 0.000 0.070
Pseudomonas_psychrotolerans 0.026 0.008 0.052
Comamonas_sediminis 0.023 0.000 0.056
Corynebacterium_kroppenstedtii 0.021 0.036 0.000
Flavobacterium_anatoliense 0.019 0.000 0.047
Sphingobacterium_multivorum 0.015 0.012 0.019
Staphylococcus_sciuri 0.015 0.026 0.000
Devosia_riboflavina 0.014 0.000 0.035
uncultured_Tistrella 0.013 0.023 0.000
uncultured_bacterium 0.010 0.014 0.003
prev_corn_species$ITS %>% 
  distinct(Species, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  filter(total >= 0.01) %>%
  arrange(desc(total)) %>%
  kbl(format = 'html', col.names = c('Species', 'Total Relative Abundance', 
                                     'Relative abundance B73', 'Relative abundance CML322')) %>%
  kable_classic(full_width = F, html_font = "Times New Roman")
Species Total Relative Abundance Relative abundance B73 Relative abundance CML322
Aspergillus_flavus 0.567 0.525 0.608
Sarocladium_zeae 0.259 0.234 0.284
Meyerozyma_caribbica 0.135 0.168 0.102
Aspergillus_niger 0.011 0.021 0.000
Talaromyces_purpureogenus 0.010 0.019 0.000

Below are barplots of relative taxon abundances for 16S sequencing with samples grouped according to similarity using the neatmap method.

## https://github.com/google/palette.js/blob/79a703df344e3b24380ce1a211a2df7f2d90ca22/palette.js#L802
mpn65 = c('#ff0029','#377eb8','#66a61e','#984ea3','#00d2d5','#ff7f00','#af8d00','#7f80cd','#b3e900','#c42e60','#a65628',
         '#f781bf','#8dd3c7','#bebada','#fb8072','#80b1d3','#fdb462','#fccde5','#bc80bd','#ffed6f','#c4eaff','#cf8c00',
         '#f2b94f','#eff26e','#e43872','#d9b100','#9d7a00','#698cff','#d9d9d9','#00d27e','#d06800','#009f82','#c49200',
         '#cbe8ff','#fecddf','#c27eb6','#8cd2ce','#c4b8d9','#f883b0','#a49100','#f48800','#27d0df','#a04a9b')
map(rank_names(ps_genus$`16S`)[2:6], function(tax_rank){
  df = ps_genus$`16S` %>% 
    speedyseq::mutate_sample_data(condition = condition_w_rep) %>%
    transform(transform = "compositional") %>%
  p = plot_composition(df, x.label='condition', otu.sort = 'abundance', sample.sort='neatmap') +
  guides(fill = guide_legend(ncol = 1)) +
  scale_fill_manual(values=mpn65) +
  theme_minimal() + 
  theme(axis.text.x=element_text(angle=90,hjust=0, vjust=0.5)) +
  labs(x = "Sample condition",
       fill = tax_rank)
})
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]
NA







The next two sets are done with ITS counts but made the same way as above.

map(rank_names(ps_genus$ITS)[2:6], function(tax_rank){
  df = ps_genus$ITS %>% 
    speedyseq::mutate_sample_data(condition = condition_w_rep) %>%
    transform(transform = "compositional") %>%
  p = plot_composition(df, x.label='condition', otu.sort = 'abundance', sample.sort='neatmap') +
  guides(fill = guide_legend(ncol = 1)) +
  scale_fill_manual(values=mpn65) +
  theme_minimal() + 
  labs(x = "Sample condition",
       y = "Relative abundance",
       title = glue("ITS Relative abundance at {tax_rank} level"), 
       fill = tax_rank)
  p %>% plotly::ggplotly()
})
Warning: stress is (nearly) zero: you may have insufficient data
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]
NA
prune_taxa(names(sort(taxa_sums(ps_genus_ra$`16S`),decreasing = TRUE)[1:30]), ps_genus_ra$`16S`) %>%
  speedyseq::plot_heatmap(method = "NMDS", distance = "bray", sample.label = 'condition', taxa.label='Genus') +
  theme(axis.text.x=element_text(angle=90,hjust=0, vjust=0.5, size = 10),
        strip.text.x = element_text(size = 16), plot.title = element_text(size=22)) +
  labs(title = '16S Heatmap of top 30 most abundant genera')







prune_taxa(names(sort(taxa_sums(ps_genus_ra$ITS),decreasing = TRUE)[1:30]), ps_genus_ra$ITS) %>%
  speedyseq::plot_heatmap(method = "NMDS", distance = "bray", sample.label = 'condition', taxa.label='Genus') +
  theme(axis.text.x=element_text(angle=90,hjust=0, vjust=0.5, size = 10),
        strip.text.x = element_text(size = 16), plot.title = element_text(size=22)) +
  labs(title = 'ITS Heatmap of top 30 most abundant genera')

save.image(here('src/16_and_ITS_import.RData'))
LS0tDQp0aXRsZTogIjE2UyBhbmQgSVRTIGRhdGEgaW1wb3J0Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICBlZGl0b3Jfb3B0aW9uczogDQogICAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KHFpaW1lMlIpDQpsaWJyYXJ5KGdnZWFzeSkNCmxpYnJhcnkocGh5bG9zZXEpDQpsaWJyYXJ5KEJpb3N0cmluZ3MpDQpsaWJyYXJ5KGdnc2lnbmlmKQ0KbGlicmFyeShnZ2Vhc3kpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShwYXRjaHdvcmspDQpsaWJyYXJ5KERFU2VxMikNCmxpYnJhcnkoQUxERXgyKQ0KbGlicmFyeShtaWNyb2Jpb21lKSANCmxpYnJhcnkodmVnYW4pDQpsaWJyYXJ5KEFOQ09NQkMpDQpsaWJyYXJ5KGdsdWUpDQpsaWJyYXJ5KGdnc3RhdHNwbG90KQ0KbGlicmFyeShiZWVzd2FybSkNCmxpYnJhcnkobXNhKQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShnZ3RleHQpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KHRpZHlIZWF0bWFwKQ0KbGlicmFyeShTcGllY0Vhc2kpDQpsaWJyYXJ5KE5ldENvTWkpDQpsaWJyYXJ5KGlncmFwaCkNCmxpYnJhcnkodGlkeWdyYXBoKQ0KbGlicmFyeShnZ3JhcGgpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcucmV0aW5hID0gMSwgZHBpPTQ1MCkNCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybT1GKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KCkpDQpzZXNzaW9uSW5mbygpICU+JQ0KICBjYXB0dXJlLm91dHB1dChzZXNzaW9uSW5mbygpKSAlPiUNCiAgd3JpdGVfbGluZXMoaGVyZSgnb3V0cHV0L3Nlc3Npb25faW5mby50eHQnKSkNCmBgYA0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQptZXRhZGF0YSA9IHJlYWRfdHN2KGhlcmUoJ2RhdGEnLCAnbWV0YWRhdGFfbWVyZ2VkLnRzdicpLCBjb2xfdHlwZXMgPSBjb2xzKCkpICU+JQ0KICByZW5hbWUoVGltZVBvaW50ID0gVGltZXBvaW50KSAlPiUNCiAgbXV0YXRlKFRpbWVQb2ludCA9IHN0cl9yZXBsYWNlKFRpbWVQb2ludCwgJ14nLCAnVCcpLA0KICAgICAgICAgY29uZGl0aW9uID0gc3RyX2MoQ29yblZhcmlldHksIEZ1bmdhbFN0cmFpbiwgVGlzc3VlRXh0cmFjdGlvbiwgc2VwPSdfJykpICU+JQ0KICByZW5hbWUoQ29ybl9HZW5vdHlwZSA9IENvcm5WYXJpZXR5LCBGdW5nYWxfVHJlYXRtZW50ID0gRnVuZ2FsU3RyYWluLCBUaXNzdWVfRXh0cmFjdGlvbiA9IFRpc3N1ZUV4dHJhY3Rpb24pDQpgYGANCg0KYGBge3J9DQpnZXRfY291bnRzID0gZnVuY3Rpb24oLikgb3R1X3RhYmxlKC4pICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbignZmVhdHVyZV9pZCcpICU+JSBhc190aWJibGUoKQ0KZ2V0X3RheCA9IGZ1bmN0aW9uKC4pIHRheF90YWJsZSguKSAlPiUgZGF0YS5mcmFtZSgpICU+JSByb3duYW1lc190b19jb2x1bW4oJ2ZlYXR1cmVfaWQnKSAlPiUgYXNfdGliYmxlKCkNCmdldF9xemEgPSBmdW5jdGlvbihmaWxlcGF0aCl7cmVhZF9xemEoZmlsZXBhdGgpJGRhdGEgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCdTYW1wbGVJRCcpfQ0KZ2V0X3NhbXBsZV9kYXRhID0gZnVuY3Rpb24oLikgZGF0YS5mcmFtZShzYW1wbGVfZGF0YSguKSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbignU2FtcGxlSUQnKSAlPiUgYXNfdGliYmxlKCkNCmNoYW5nZV9pdHNfaWRzX3RvX21hdGNoXzE2UyA9IC4gJT4lIA0KICBtdXRhdGUoU2FtcGxlSUQgPSBzdHJfcmVwbGFjZShTYW1wbGVJRCwgJyguKj8pLSguKiknLCAnXFwyLVxcMScpLA0KICAgICAgICAgU2FtcGxlSUQgPSBzdHJfcmVwbGFjZV9hbGwoU2FtcGxlSUQsIGMoJy1CNzMnPSctMzczJywgJy1DMzIyJz0nLTMyMicpKSkNCmNoYW5nZV8xNlNfaWRzX3RvX21hdGNoX0lUUyA9IC4gJT4lIA0KICBtdXRhdGUoU2FtcGxlSUQgPSBzdHJfcmVwbGFjZShTYW1wbGVJRCwgJyguKj8pLSguKiknLCAnXFwyLVxcMScpLA0KICAgICAgICAgU2FtcGxlSUQgPSBzdHJfcmVwbGFjZV9hbGwoU2FtcGxlSUQsIGMoJy0zNzMnPSctQjczJywgJy0zMjInPSctQzMyMicpKSkNCmBgYA0KDQpgYGB7cn0NCnBzID0gbGlzdCgnMTZTJz0gcXphX3RvX3BoeWxvc2VxKGZlYXR1cmVzID0gaGVyZSgnZGF0YScsICcxNlMnLCAndGFibGVfd29fb3V0bGllcnMucXphJyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRyZWU9aGVyZSgnZGF0YScsICcxNlMnLCAncm9vdGVkLXRyZWUucXphJyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRheG9ub215PWhlcmUoJ2RhdGEnLCAnMTZTJywgJ21lcmdlZC10YXhvbm9teS5xemEnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE9aGVyZSgnZGF0YScsICcxNlMnLCAnbWV0YWRhdGFfZmlsdGVyZWQudHN2JyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRtcD0nQzovVXNlcnMvYnJpYW4ubWFjay9Eb3dubG9hZHMvdG1wJykgJT4lIA0KICAgICAgICAgICAgc3Vic2V0X3NhbXBsZXMoQ29yblZhcmlldHkgIT0gJ2R1bW15JyAmIFRpbWVwb2ludCA9PSAnMicgJiBUaXNzdWVUeXBlID09ICdPdnVsZScpICU+JQ0KICAgICAgICAgICAgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKSwNCiAgICAgICAgICAnSVRTJyA9IHF6YV90b19waHlsb3NlcShmZWF0dXJlcyA9IGhlcmUoJ2RhdGEnLCAnSVRTJywgJ3RhYmxlLW5vLW1pdG9jaG9uZHJpYS1uby1jaGxvcm9wbGFzdC5xemEnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJlZT1oZXJlKCdkYXRhJywgJ0lUUycsICdyb290ZWQtdHJlZS5xemEnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGF4b25vbXk9aGVyZSgnZGF0YScsICdJVFMnLCAnbWVyZ2VkLXRheG9ub215LnF6YScpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YT1oZXJlKCdkYXRhJywgJ0lUUycsICdtZXRhZGF0YV9tZXJnZWQudHN2JyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRtcD0nQzovVXNlcnMvYnJpYW4ubWFjay9Eb3dubG9hZHMvdG1wJykgICU+JSANCiAgICAgICAgICAgIHN1YnNldF9zYW1wbGVzKENvcm5WYXJpZXR5ICAhPSAnZHVtbXknICYgVGltZXBvaW50ID09ICcyJyAmIFRpc3N1ZVR5cGUgPT0gJ092dWxlJykgJT4lDQogICAgICAgICAgICBwcnVuZV90YXhhKHRheGFfc3VtcyguKSA+IDAsIC4pDQogICAgICAgICAgICApDQpwcyA9IG1hcChwcywgZnVuY3Rpb24oLngpew0KICBzYW1wbGVfZGF0YSgueCkgPSBnZXRfc2FtcGxlX2RhdGEoLngpICU+JSANCiAgICByZW5hbWUoVGltZVBvaW50ID0gVGltZXBvaW50KSAlPiUNCiAgICBtdXRhdGUoVGltZVBvaW50ID0gc3RyX3JlcGxhY2UoVGltZVBvaW50LCAnXicsICdUJyksDQogICAgICAgICAgIGNvbmRpdGlvbiA9IHN0cl9jKENvcm5WYXJpZXR5LCBGdW5nYWxTdHJhaW4sIFRpc3N1ZUV4dHJhY3Rpb24sIHNlcD0nXycpKSAlPiUNCiAgICByZW5hbWUoQ29ybl9HZW5vdHlwZSA9IENvcm5WYXJpZXR5LCBGdW5nYWxfVHJlYXRtZW50ID0gRnVuZ2FsU3RyYWluLCBUaXNzdWVfRXh0cmFjdGlvbiA9IFRpc3N1ZUV4dHJhY3Rpb24pICU+JQ0KICAgIGdyb3VwX2J5KGNvbmRpdGlvbikgJT4lDQogICAgbXV0YXRlKGJpb2xvZ2ljYWxfcmVwID0gcm93X251bWJlcigpKSAlPiUNCiAgICB1bmdyb3VwKCkgJT4lDQogICAgbXV0YXRlKGNvbmRpdGlvbl93X3JlcCA9IHN0cl9jKGNvbmRpdGlvbiwgYmlvbG9naWNhbF9yZXAsIHNlcD0nXycpKSAlPiUNCiAgICBjb2x1bW5fdG9fcm93bmFtZXMoJ1NhbXBsZUlEJykNCiAgcmV0dXJuKC54KX0pDQpzYW1wbGVfZGF0YShwcyRJVFMpID0gZ2V0X3NhbXBsZV9kYXRhKHBzJElUUykgJT4lDQogIGNoYW5nZV9pdHNfaWRzX3RvX21hdGNoXzE2UygpICU+JQ0KICBjb2x1bW5fdG9fcm93bmFtZXMoJ1NhbXBsZUlEJykNCnJlYWRzX2RmID0gcmVhZHMgJT4lIG1hcCh+dGliYmxlKHNlcXVlbmNlID0gYXMuY2hhcmFjdGVyKC54KSwgZmVhdHVyZV9pZCA9IG5hbWVzKC54KSkpDQpwcyAlPiUgaW1hcCh+Z2V0X2NvdW50cygueCkgJT4lIA0KICAgICAgICAgICAgICBsZWZ0X2pvaW4ocmVhZHNfZGZbWy55XV0sIGJ5PSdmZWF0dXJlX2lkJykgJT4lDQogICAgICAgICAgICAgIGxlZnRfam9pbihnZXRfdGF4KC54KSwgYnk9J2ZlYXR1cmVfaWQnKSAlPiUNCiAgICAgICAgICAgICAgcmVuYW1lKGFsbF9vZihnZXRfc2FtcGxlX2RhdGEoLngpICU+JSBwdWxsKFNhbXBsZUlELCBuYW1lPWNvbmRpdGlvbl93X3JlcCkpKSAlPiUNCiAgICAgICAgICAgICAgd3JpdGVfY3N2KGhlcmUoc3RyX2dsdWUoJ291dHB1dC9yYXdfY291bnRzX2FuZF90YXhvbm9teV97Lnl9LmNzdicpKSkNCiAgICAgICAgICAgICAgKQ0KYGBgDQoNClJlbW92ZWQgdGF4YSBub3QgYXNzaWduZWQgdG8gYSBwaHlsdW0uIEFmdGVyIHJlbW92aW5nIHRoZXNlIHRheGEsIDEgMTZTIHNhbXBsZXMgd2FzIHJlbW92ZWQgZHVlIHRvIGhhdmluZyB0b3RhbCBjb3VudHMgPD0gMTUwMC4NCg0KYGBge3J9DQpwc19waHlsdW1fZmlsdCA9IGxpc3QoJzE2UycgPSBzdWJzZXRfdGF4YShwcyRgMTZTYCwgIWlzLm5hKFBoeWx1bSkgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIVBoeWx1bSAlaW4lIGMoJycsICd1bmNoYXJhY3Rlcml6ZWQnLCAndW5pZGVudGlmaWVkJykgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIUtpbmdkb20gJWluJSBjKCdkX19FdWthcnlvdGEnKSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyguKSA+PSAxNTAwLCAuKSAlPiUgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKSwNCiAgICAgICAgICAgICAgICAgICAgICAnSVRTJyA9IHN1YnNldF90YXhhKHBzJElUUywgIWlzLm5hKFBoeWx1bSkgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhUGh5bHVtICVpbiUgYygiIiwgJ3VuY2hhcmFjdGVyaXplZCcsICd1bmlkZW50aWZpZWQnKSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyguKSA+PSAxNTAwLCAuKSAlPiUgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKSkNCnBzX3BoeWx1bV9maWx0X3RheCA9IHBzX3BoeWx1bV9maWx0ICU+JSBtYXAoZ2V0X3RheCkNCnBzX3BoeWx1bV9maWx0X2NvdW50cyA9IHBzX3BoeWx1bV9maWx0ICU+JSBtYXAoZ2V0X2NvdW50cykNCnBzX3BoeWx1bV9maWx0X3JhID0gbWFwKHBzX3BoeWx1bV9maWx0LCB+dHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoLngsIGZ1bmN0aW9uKHgpe3ggLyBzdW0oeCl9KSkNCnBzX3BoeWx1bV9maWx0DQpgYGANCmBgYHtyfQ0KcmVhZHMgPSBsaXN0KCcxNlMnID0gcmVhZF9xemEoaGVyZSgnZGF0YScsICcxNlMnLCAncmVwLXNlcXMtZmlsdGVyZWQucXphJykpJGRhdGEsDQogICAgICAgICAgICAgJ0lUUycgPSByZWFkX3F6YShoZXJlKCdkYXRhJywgJ0lUUycsICdyZXAtc2Vxcy1maWx0ZXJlZC5xemEnKSkkZGF0YSkNCmBgYA0KDQpgYGB7cn0NCnBzX3BoeWx1bV9maWx0ICU+JSBpbWFwKGZ1bmN0aW9uKHBzX3BoeWx1bV9maWx0LCBzZXFfdHlwZSl7DQogIHBzX3BoeWx1bV9maWx0ICU+JSBnZXRfdGF4KCkgJT4lDQogICAgc3VtbWFyaXplKGFjcm9zcygtZmVhdHVyZV9pZCwgfnN1bSghaXMubmEoLngpKS8gbigpKSkgJT4lDQogICAgcm91bmQoMikgJT4lDQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAnVGF4b25vbWljIHJhbmsnLCB2YWx1ZXNfdG8gPSBzZXFfdHlwZSkNCiAgfSkgJT4lDQogIHJlZHVjZShmdWxsX2pvaW4sIGJ5PSdUYXhvbm9taWMgcmFuaycpICU+JQ0KICBrYmwoZm9ybWF0ID0gJ2h0bWwnLCBjYXB0aW9uPSdGcmFjdGlvbiBvZiBBU1ZzIGNsYXNzaWZpZWQgYXQgZWFjaCByYW5rJykgJT4lDQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEYsIGh0bWxfZm9udCA9ICJUaW1lcyBOZXcgUm9tYW4iKSANCmBgYA0KDQpgYGB7ciwgZmlnLmhlaWdodD02fQ0KcHNfcGh5bHVtX2ZpbHQgJT4lIGltYXAoZnVuY3Rpb24ocHNfcGh5bHVtX2ZpbHQsIHNlcV90eXBlKXsNCiAgcHNfcGh5bHVtX2ZpbHQgJT4lIHNhbXBsZV9zdW1zKCkgJT4lIGVuZnJhbWUobmFtZSA9ICdTYW1wbGVJRCcsIHZhbHVlID0gJ3RvdGFsX2NvdW50cycpICU+JQ0KICAgIGxlZnRfam9pbihtZXRhZGF0YSwgYnk9J1NhbXBsZUlEJykgJT4lDQogICAgbXV0YXRlKHNlcV90eXBlID0gc2VxX3R5cGUpDQogIH0pICU+JQ0KICBiaW5kX3Jvd3MoKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbiwgeT10b3RhbF9jb3VudHMpKSArDQogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsNCiAgZ2diZWVzd2FybTo6Z2VvbV9xdWFzaXJhbmRvbShhbHBoYSA9IDAuMywgd2lkdGg9MC4yLCBncm91cE9uWD1UUlVFKSArDQogIGZhY2V0X3dyYXAofnNlcV90eXBlLCBuY29sPTEsIHNjYWxlcyA9ICdmcmVlJykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICBsYWJzKHRpdGxlPSdUb3RhbCBudW1iZXIgb2YgY291bnRzIGZvciBlYWNoIHNhbXBsZScpICsNCiAgZ2dlYXN5OjplYXN5X3JvdGF0ZV94X2xhYmVscygpICsNCiAgZ2dlYXN5OjplYXN5X2NlbnRlcl90aXRsZSgpDQpgYGANCg0KPGJyPjxicj48YnI+DQoNClJhcmVmeWluZyB0byAxNTY5IGNvdW50cy4NCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpwc19waHlsdW1fZmlsdF9yYXJlZmllZCA9ICBwc19waHlsdW1fZmlsdCAlPiUgbWFwKA0KICB+cmFyZWZ5X2V2ZW5fZGVwdGgoLngsIHNhbXBsZS5zaXplID0gMTU2OSwgcm5nc2VlZD0xMTAwICwgcmVwbGFjZT1GQUxTRSkgJT4lDQogICAgIHBydW5lX3RheGEodGF4YV9zdW1zKC4pID4gMCwgLikpDQpwc19waHlsdW1fZmlsdF9yYXJlZmllZA0KYGBgDQoNCjxicj48YnI+PGJyPjxicj48YnI+PGJyPg0KDQpgYGB7ciwgZmlnLndpZHRoPTEyfQ0KcHJldiA9IG1hcChwc19waHlsdW1fZmlsdF9yYSwNCiAgICAgICAgICAgIGZ1bmN0aW9uKHBzX3BoeWx1bV9maWx0X3JhKXsNCiAgICAgICAgICAgICAgcmVsYXRpdmVfY291bnRzID0gcHNfcGh5bHVtX2ZpbHRfcmEgJT4lIGdldF9jb3VudHMoKQ0KICAgICAgICAgICAgICB0YXggPSBwc19waHlsdW1fZmlsdF9yYSAlPiUgZ2V0X3RheCgpDQogICAgICAgICAgICAgIHJlbGF0aXZlX2NvdW50cyAlPiUgDQogICAgICAgICAgICAgICAgcmVmcmFtZShmZWF0dXJlX2lkID0gZmVhdHVyZV9pZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2YWxlbmNlID0gcm93U3VtcyguPiAwKSAtMSwgI3N1YnRyYWN0ZWQgMSBiZWNhdXNlIGZlYXR1cmVfaWQgY29sdW1uIGlzIGFsd2F5cyBjb3VudGVkDQogICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfcmVsYXRpdmVfYWJ1bmRhbmNlID0gdGF4YV9zdW1zKHBzX3BoeWx1bV9maWx0X3JhKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgUGh5bHVtID0gdGF4JFBoeWx1bSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBHZW51cyA9IHRheCRHZW51cywNCiAgICAgICAgICAgICAgICAgICAgICAgICBTcGVjaWVzID0gdGF4JFNwZWNpZXMpfSkNCnByZXZfcGxvdHMgPSBwcmV2ICU+JSBpbWFwKGZ1bmN0aW9uKHByZXYsIHNlcV90eXBlKXsNCiAgcHJldiAlPiUgDQogICAgbXV0YXRlKHByZXZhbGVuY2UgPSBwcmV2YWxlbmNlIC8gbnNhbXBsZXMocHNfcGh5bHVtX2ZpbHRbW3NlcV90eXBlXV0pKSAlPiUNCiAgZ2dwbG90KGFlcyh0b3RhbF9yZWxhdGl2ZV9hYnVuZGFuY2UsIHByZXZhbGVuY2UsIGNvbG9yPVBoeWx1bSwgdGV4dD1nbHVlKCdHZW51czoge0dlbnVzfTxicj5TcGVjaWVzOiB7U3BlY2llc30nKSkpICsNCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjA1LCBhbHBoYSA9IDAuNSwgbGluZXR5cGUgPSAyKSArIA0KICAgIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGFscGhhID0gMC42KSArDQogICAgc2NhbGVfeF9sb2cxMCgpICsgeGxhYigiVG90YWwgUmVsYXRpdmUgQWJ1bmRhbmNlIikgKyB5bGFiKCJQcmV2YWxlbmNlIFtGcmFjdGlvbiBTYW1wbGVzXSIpICsNCiAgICBmYWNldF93cmFwKH5QaHlsdW0pICsNCiAgICBsYWJzKHRpdGxlID0gZ2x1ZSgne3NlcV90eXBlfSBBU1YgUHJldmFsZW5jZScpKSArDQogICAgdGhlbWVfZ3JheSgpICsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpfSkNCmBgYA0KDQpgYGB7ciwgb3V0LndpZHRoPTEyfQ0KcHJldl9wbG90cyRgMTZTYCAlPiUgcGxvdGx5OjpnZ3Bsb3RseSgpDQpgYGANCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCnByZXZfcGxvdHMkSVRTICU+JSBwbG90bHk6OmdncGxvdGx5KCkNCmBgYA0KUHJlZG9taW5hbnQgcGh5bGENCmBgYHtyfQ0KcHNfcGh5bGEgPSBtYXAocHNfcGh5bHVtX2ZpbHQsIA0KICAgICAgICAgICAgICAgZnVuY3Rpb24ocHNfcGh5bHVtX2ZpbHQpew0KICAgICAgICAgICAgICAgICBwc19waHlsYSA9IHRheF9nbG9tKHBzX3BoeWx1bV9maWx0LCAiUGh5bHVtIiwgTkFybSA9IFRSVUUpDQogICAgICAgICAgICAgICAgIHByZXZhbGVuY2VUaHJlc2hvbGQgPSAgMC4wNSAqIG5zYW1wbGVzKHBzX3BoeWxhKQ0KICAgICAgICAgICAgICAgICBwc19waHlsYSA9IHBzX3BoeWxhICU+JSANCiAgICAgICAgICAgICAgICAgICBnZXRfY291bnRzKCkgJT4lIA0KICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShmZWF0dXJlX2lkID0gZmVhdHVyZV9pZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmFsZW5jZSA9IHJvd1N1bXMoLj4gMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRvdGFsQWJ1bmRhbmNlID0gdGF4YV9zdW1zKHBzX3BoeWxhKSkgJT4lDQogICAgICAgICAgICAgICAgICAgZmlsdGVyKHByZXZhbGVuY2UgPj0gcHJldmFsZW5jZVRocmVzaG9sZCkgJT4lIA0KICAgICAgICAgICAgICAgICAgIHB1bGwoZmVhdHVyZV9pZCkgJT4lDQogICAgICAgICAgICAgICAgICAgcHJ1bmVfdGF4YSguLCBwc19waHlsYSkgJT4lDQogICAgICAgICAgICAgICAgICAgcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyguKSA+PSA1MDAsIC4pICU+JSANCiAgICAgICAgICAgICAgICAgICBwcnVuZV90YXhhKHRheGFfc3VtcyguKSA+IDAsIC4pDQogICAgICAgICAgICAgICAgIHNhbXBsZV9kYXRhKHBzX3BoeWxhKSA9IHNhbXBsZV9kYXRhKHBzX3BoeWxhKSAlPiUgDQogICAgICAgICAgICAgICAgICAgYXMoJ2RhdGEuZnJhbWUnKSAlPiUNCiAgICAgICAgICAgICAgICAgICBtdXRhdGUoVGlzc3VlVHlwZSA9IGZjdF9yZWxldmVsKFRpc3N1ZVR5cGUsICdPdnVsZScpKQ0KICAgICAgICAgICAgICAgICByZXR1cm4ocHNfcGh5bGEpfSkNCnBzX3BoeWxhX3JhID0gbWFwKHBzX3BoeWxhLCB+dHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoLngsIGZ1bmN0aW9uKHgpe3ggLyBzdW0oeCl9KSkNCnByZXZfY29ybl9waHlsYSA9IG1hcChwc19waHlsYV9yYSwNCiAgICAgICAgICAgIGZ1bmN0aW9uKHBzX3BoeWxhX3JhKXsNCiAgICAgICAgICAgIHJlbGF0aXZlX2NvdW50cyA9IHBzX3BoeWxhX3JhICU+JSBnZXRfY291bnRzKCkNCiAgICAgICAgICAgICAgdGF4ID0gcHNfcGh5bGFfcmEgJT4lIGdldF90YXgoKQ0KICAgICAgICAgICAgICByZWxhdGl2ZV9jb3VudHMgJT4lIA0KICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcigtZmVhdHVyZV9pZCwgbmFtZXNfdG8gPSAnU2FtcGxlSUQnLCB2YWx1ZXNfdG8gPSAnY291bnRzJykgJT4lDQogICAgICAgICAgICAgICAgbGVmdF9qb2luKG1ldGFkYXRhLCBieT0nU2FtcGxlSUQnKSAlPiUNCiAgICAgICAgICAgICAgICBsZWZ0X2pvaW4odGF4LCBieT0nZmVhdHVyZV9pZCcpICU+JQ0KICAgICAgICAgICAgICAgIGdyb3VwX2J5KFBoeWx1bSkgJT4lDQogICAgICAgICAgICAgICAgbXV0YXRlKHByZXZhbGVuY2VfZW50aXJlX2RhdGFzZXQgPSBzdW0oY291bnRzID4gMCkgLyBuKCksDQogICAgICAgICAgICAgICAgICAgICAgIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0ID0gbWVhbihjb3VudHMpKSAlPiUNCiAgICAgICAgICAgICAgICBncm91cF9ieShQaHlsdW0sIENvcm5fR2Vub3R5cGUpICU+JQ0KICAgICAgICAgICAgICAgIHN1bW1hcml6ZShwcmV2YWxlbmNlID0gc3VtKGNvdW50cyA+IDApIC8gbigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSA9IG1lYW4oY291bnRzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmFsZW5jZV9lbnRpcmVfZGF0YXNldCA9IGZpcnN0KHByZXZhbGVuY2VfZW50aXJlX2RhdGFzZXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCA9IGZpcnN0KG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0KSkgJT4lDQogICAgICAgICAgICAgICAgdW5ncm91cCgpfSkNCnByZXZfY29ybl9waHlsYSRgMTZTYCAlPiUgDQogIHJlbmFtZSh0b3RhbCA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0KSAlPiUNCiAgZGlzdGluY3QoUGh5bHVtLCBDb3JuX0dlbm90eXBlLCBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSwgdG90YWwpICU+JQ0KICBtdXRhdGUobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2U9IHJvdW5kKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCAzKSwNCiAgICAgICAgIHRvdGFsID0gcm91bmQodG90YWwsIDMpKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IENvcm5fR2Vub3R5cGUsIHZhbHVlc19mcm9tID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UpICU+JQ0KICBmaWx0ZXIodG90YWwgPj0gMC4wMSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JQ0KICBrYmwoZm9ybWF0ID0gJ2h0bWwnLCBjb2wubmFtZXMgPSBjKCdQaHlsdW0nLCAnVG90YWwgUmVsYXRpdmUgQWJ1bmRhbmNlJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JlbGF0aXZlIGFidW5kYW5jZSBCNzMnLCAnUmVsYXRpdmUgYWJ1bmRhbmNlIENNTDMyMicpKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIlRpbWVzIE5ldyBSb21hbiIpDQpwcmV2X2Nvcm5fcGh5bGEkSVRTICU+JSANCiAgcmVuYW1lKHRvdGFsID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQpICU+JQ0KICBkaXN0aW5jdChQaHlsdW0sIENvcm5fR2Vub3R5cGUsIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCB0b3RhbCkgJT4lDQogIG11dGF0ZShtZWFuX3JlbGF0aXZlX2FidW5kYW5jZT0gcm91bmQobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIDMpLA0KICAgICAgICAgdG90YWwgPSByb3VuZCh0b3RhbCwgMykpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ29ybl9HZW5vdHlwZSwgdmFsdWVzX2Zyb20gPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSkgJT4lDQogICNmaWx0ZXIodG90YWwgPj0gMC4wMSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JQ0KICBrYmwoZm9ybWF0ID0gJ2h0bWwnLCBjb2wubmFtZXMgPSBjKCdQaHlsdW0nLCAnVG90YWwgUmVsYXRpdmUgQWJ1bmRhbmNlJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JlbGF0aXZlIGFidW5kYW5jZSBCNzMnLCAnUmVsYXRpdmUgYWJ1bmRhbmNlIENNTDMyMicpKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIlRpbWVzIE5ldyBSb21hbiIpDQpgYGANCjxicj48YnI+PGJyPiBSZW1vdmVkIHRheGEgdGhhdCBhcmUgcHJlc2VudCBpbiBsZXNzIHRoYW4gNSUgb2Ygc2FtcGxlcyBmb3IgQVNWIGxldmVsIGRhdGFzZXQuIFRoaXMgd2lsbCBiZSB1c2VkIGZvciBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIHRlc3RpbmcgYXQgQVNWIGxldmVsLg0KYGBge3J9DQpwc19wcmV2ZiA9IG1hcDIocHNfcGh5bHVtX2ZpbHQsIHByZXYsDQogICAgICAgICAgICAgICBmdW5jdGlvbihwc19waHlsdW1fZmlsdCwgcHJldil7DQogICAgICAgICAgICAgICAgIHByZXZhbGVuY2VUaHJlc2hvbGQgPSAgMC4wNSAqIG5zYW1wbGVzKHBzX3BoeWx1bV9maWx0KQ0KICAgICAgICAgICAgICAgICBrZWVwVGF4YSA9IGZpbHRlcihwcmV2LCBwcmV2YWxlbmNlID49IHByZXZhbGVuY2VUaHJlc2hvbGQpICU+JSANCiAgICAgICAgICAgICAgICAgICBwdWxsKGZlYXR1cmVfaWQpDQogICAgICAgICAgICAgICAgIHBydW5lX3RheGEoa2VlcFRheGEsIHBzX3BoeWx1bV9maWx0KSAlPiUNCiAgICAgICAgICAgICAgICAgICBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKC4pID49IDUwMCwgLikgJT4lIA0KICAgICAgICAgICAgICAgICAgIHBydW5lX3RheGEodGF4YV9zdW1zKC4pID4gMCwgLil9KQ0KcHNfcHJldmZfcmEgPSBtYXAocHNfcHJldmYsIH50cmFuc2Zvcm1fc2FtcGxlX2NvdW50cygueCwgZnVuY3Rpb24oeCl7eCAvIHN1bSh4KX0pKQ0KcHNfcHJldmZfY2xyID0gbWFwKHBzX3ByZXZmLCBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0sICdjbHInKQ0KcHNfcHJldmZfYWxyID0gbWFwKHBzX3ByZXZmLCBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0sICdhbHInLCBzaGlmdD0xKQ0KcHNfcHJldmYNCmBgYA0KDQo8YnI+PGJyPjxicj4gQWdnbG9tZXJhdGVkIGNvdW50cyBhdCBib3RoIGdlbnVzIGxldmVsIGFuZCBzcGVjaWVzIGxldmVsLg0KDQpgYGB7cn0NCnBzX2dlbnVzID0gbWFwKHBzX3BoeWx1bV9maWx0LCANCiAgICAgICAgICAgICAgIGZ1bmN0aW9uKHBzX3BoeWx1bV9maWx0KXsNCiAgICAgICAgICAgICAgICAgcHNfZ2VudXMgPSB0YXhfZ2xvbShwc19waHlsdW1fZmlsdCwgIkdlbnVzIiwgTkFybSA9IFRSVUUpDQogICAgICAgICAgICAgICAgIHByZXZhbGVuY2VUaHJlc2hvbGQgPSAgMC4wNSAqIG5zYW1wbGVzKHBzX2dlbnVzKQ0KICAgICAgICAgICAgICAgICBwc19nZW51cyA9IHBzX2dlbnVzICU+JSANCiAgICAgICAgICAgICAgICAgICBnZXRfY291bnRzKCkgJT4lIA0KICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShmZWF0dXJlX2lkID0gZmVhdHVyZV9pZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmFsZW5jZSA9IHJvd1N1bXMoLj4gMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRvdGFsQWJ1bmRhbmNlID0gdGF4YV9zdW1zKHBzX2dlbnVzKSkgJT4lDQogICAgICAgICAgICAgICAgICAgZmlsdGVyKHByZXZhbGVuY2UgPj0gcHJldmFsZW5jZVRocmVzaG9sZCkgJT4lIA0KICAgICAgICAgICAgICAgICAgIHB1bGwoZmVhdHVyZV9pZCkgJT4lDQogICAgICAgICAgICAgICAgICAgcHJ1bmVfdGF4YSguLCBwc19nZW51cykgJT4lDQogICAgICAgICAgICAgICAgICAgcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyguKSA+PSA1MDAsIC4pICU+JSANCiAgICAgICAgICAgICAgICAgICBwcnVuZV90YXhhKHRheGFfc3VtcyguKSA+IDAsIC4pDQogICAgICAgICAgICAgICAgIHNhbXBsZV9kYXRhKHBzX2dlbnVzKSA9IHNhbXBsZV9kYXRhKHBzX2dlbnVzKSAlPiUgDQogICAgICAgICAgICAgICAgICAgYXMoJ2RhdGEuZnJhbWUnKSAlPiUNCiAgICAgICAgICAgICAgICAgICBtdXRhdGUoVGlzc3VlVHlwZSA9IGZjdF9yZWxldmVsKFRpc3N1ZVR5cGUsICdPdnVsZScpKQ0KICAgICAgICAgICAgICAgICByZXR1cm4ocHNfZ2VudXMpfSkNCnBzX2dlbnVzX3JhID0gbWFwKHBzX2dlbnVzLCB+dHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoLngsIGZ1bmN0aW9uKHgpe3ggLyBzdW0oeCl9KSkNCnBzX2dlbnVzX2NsciA9IG1hcChwc19nZW51cywgbWljcm9iaW9tZTo6dHJhbnNmb3JtLCAnY2xyJykNCnBzX2dlbnVzX2FsciA9IG1hcChwc19nZW51cywgbWljcm9iaW9tZTo6dHJhbnNmb3JtLCAnYWxyJywgc2hpZnQ9MSkNCnBzX3NwZWNpZXMgPSBtYXAocHNfcGh5bHVtX2ZpbHQsIA0KICAgICAgICAgICAgICAgZnVuY3Rpb24ocHNfcGh5bHVtX2ZpbHQpew0KICAgICAgICAgICAgICAgICBwc19zcGVjaWVzID0gdGF4X2dsb20ocHNfcGh5bHVtX2ZpbHQsICJTcGVjaWVzIiwgTkFybSA9IFRSVUUpDQogICAgICAgICAgICAgICAgIHByZXZhbGVuY2VUaHJlc2hvbGQgPSAgMC4wNSAqIG5zYW1wbGVzKHBzX3NwZWNpZXMpDQogICAgICAgICAgICAgICAgIHBzX3NwZWNpZXMgPSBwc19zcGVjaWVzICU+JSANCiAgICAgICAgICAgICAgICAgICBnZXRfY291bnRzKCkgJT4lIA0KICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShmZWF0dXJlX2lkID0gZmVhdHVyZV9pZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmFsZW5jZSA9IHJvd1N1bXMoLj4gMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRvdGFsQWJ1bmRhbmNlID0gdGF4YV9zdW1zKHBzX3NwZWNpZXMpKSAlPiUNCiAgICAgICAgICAgICAgICAgICBmaWx0ZXIocHJldmFsZW5jZSA+PSBwcmV2YWxlbmNlVGhyZXNob2xkKSAlPiUgDQogICAgICAgICAgICAgICAgICAgcHVsbChmZWF0dXJlX2lkKSAlPiUNCiAgICAgICAgICAgICAgICAgICBwcnVuZV90YXhhKC4sIHBzX3NwZWNpZXMpICU+JQ0KICAgICAgICAgICAgICAgICAgIHBydW5lX3NhbXBsZXMoc2FtcGxlX3N1bXMoLikgPj0gNTAwLCAuKSAlPiUgDQogICAgICAgICAgICAgICAgICAgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKQ0KICAgICAgICAgICAgICAgICBzYW1wbGVfZGF0YShwc19zcGVjaWVzKSA9IHNhbXBsZV9kYXRhKHBzX3NwZWNpZXMpICU+JSANCiAgICAgICAgICAgICAgICAgICBhcygnZGF0YS5mcmFtZScpICU+JQ0KICAgICAgICAgICAgICAgICAgIG11dGF0ZShUaXNzdWVUeXBlID0gZmN0X3JlbGV2ZWwoVGlzc3VlVHlwZSwgJ092dWxlJykpDQogICAgICAgICAgICAgICAgIHJldHVybihwc19zcGVjaWVzKX0pDQpwc19zcGVjaWVzX3JhID0gbWFwKHBzX3NwZWNpZXMsIH50cmFuc2Zvcm1fc2FtcGxlX2NvdW50cygueCwgZnVuY3Rpb24oeCl7eCAvIHN1bSh4KX0pKQ0KcHNfc3BlY2llc19jbHIgPSBtYXAocHNfc3BlY2llcywgbWljcm9iaW9tZTo6dHJhbnNmb3JtLCAnY2xyJykNCnBzX3NwZWNpZXNfYWxyID0gbWFwKHBzX3NwZWNpZXMsIG1pY3JvYmlvbWU6OnRyYW5zZm9ybSwgJ2FscicsIHNoaWZ0PTEpDQpgYGANCg0KTW9zdCBwcmV2YWxlbnQgZ2VuZXJhDQpgYGB7cn0NCnByZXZfY29ybl9nZW51cyA9IG1hcChwc19nZW51c19yYSwNCiAgICAgICAgICAgIGZ1bmN0aW9uKHBzX2dlbnVzX3JhKXsNCiAgICAgICAgICAgIHJlbGF0aXZlX2NvdW50cyA9IHBzX2dlbnVzX3JhICU+JSBnZXRfY291bnRzKCkNCiAgICAgICAgICAgICAgdGF4ID0gcHNfZ2VudXNfcmEgJT4lIGdldF90YXgoKQ0KICAgICAgICAgICAgICByZWxhdGl2ZV9jb3VudHMgJT4lIA0KICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcigtZmVhdHVyZV9pZCwgbmFtZXNfdG8gPSAnU2FtcGxlSUQnLCB2YWx1ZXNfdG8gPSAnY291bnRzJykgJT4lDQogICAgICAgICAgICAgICAgbGVmdF9qb2luKG1ldGFkYXRhLCBieT0nU2FtcGxlSUQnKSAlPiUNCiAgICAgICAgICAgICAgICBsZWZ0X2pvaW4odGF4LCBieT0nZmVhdHVyZV9pZCcpICU+JQ0KICAgICAgICAgICAgICAgIGdyb3VwX2J5KEdlbnVzKSAlPiUNCiAgICAgICAgICAgICAgICBtdXRhdGUocHJldmFsZW5jZV9lbnRpcmVfZGF0YXNldCA9IHN1bShjb3VudHMgPiAwKSAvIG4oKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQgPSBtZWFuKGNvdW50cykpICU+JQ0KICAgICAgICAgICAgICAgIGdyb3VwX2J5KEdlbnVzLCBDb3JuX0dlbm90eXBlKSAlPiUNCiAgICAgICAgICAgICAgICBzdW1tYXJpemUocHJldmFsZW5jZSA9IHN1bShjb3VudHMgPiAwKSAvIG4oKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UgPSBtZWFuKGNvdW50cyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHByZXZhbGVuY2VfZW50aXJlX2RhdGFzZXQgPSBmaXJzdChwcmV2YWxlbmNlX2VudGlyZV9kYXRhc2V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQgPSBmaXJzdChtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCkpICU+JQ0KICAgICAgICAgICAgICAgIHVuZ3JvdXAoKX0pDQpwcmV2X2Nvcm5fZ2VudXMkYDE2U2AgJT4lIA0KICByZW5hbWUodG90YWwgPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCkgJT4lDQogIGRpc3RpbmN0KEdlbnVzLCBDb3JuX0dlbm90eXBlLCBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSwgdG90YWwpICU+JQ0KICBtdXRhdGUobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2U9IHJvdW5kKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCAzKSwNCiAgICAgICAgIHRvdGFsID0gcm91bmQodG90YWwsIDMpKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IENvcm5fR2Vub3R5cGUsIHZhbHVlc19mcm9tID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UpICU+JQ0KICBmaWx0ZXIodG90YWwgPj0gMC4wMSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JQ0KICBrYmwoZm9ybWF0ID0gJ2h0bWwnLCBjb2wubmFtZXMgPSBjKCdHZW51cycsICdUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmVsYXRpdmUgYWJ1bmRhbmNlIEI3MycsICdSZWxhdGl2ZSBhYnVuZGFuY2UgQ01MMzIyJykpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiVGltZXMgTmV3IFJvbWFuIikNCnByZXZfY29ybl9nZW51cyRJVFMgJT4lIA0KICByZW5hbWUodG90YWwgPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCkgJT4lDQogIGRpc3RpbmN0KEdlbnVzLCBDb3JuX0dlbm90eXBlLCBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSwgdG90YWwpICU+JQ0KICBtdXRhdGUobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2U9IHJvdW5kKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCAzKSwNCiAgICAgICAgIHRvdGFsID0gcm91bmQodG90YWwsIDMpKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IENvcm5fR2Vub3R5cGUsIHZhbHVlc19mcm9tID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UpICU+JQ0KICAjZmlsdGVyKHRvdGFsID49IDAuMDEpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWwpKSAlPiUNCiAga2JsKGZvcm1hdCA9ICdodG1sJywgY29sLm5hbWVzID0gYygnR2VudXMnLCAnVG90YWwgUmVsYXRpdmUgQWJ1bmRhbmNlJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JlbGF0aXZlIGFidW5kYW5jZSBCNzMnLCAnUmVsYXRpdmUgYWJ1bmRhbmNlIENNTDMyMicpKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIlRpbWVzIE5ldyBSb21hbiIpDQpgYGANCk1vc3QgcHJldmFsZW50IHNwZWNpZXMNCmBgYHtyfQ0KcHJldl9jb3JuX3NwZWNpZXMgPSBtYXAocHNfc3BlY2llc19yYSwNCiAgICAgICAgICAgIGZ1bmN0aW9uKHBzX3NwZWNpZXNfcmEpew0KICAgICAgICAgICAgcmVsYXRpdmVfY291bnRzID0gcHNfc3BlY2llc19yYSAlPiUgZ2V0X2NvdW50cygpDQogICAgICAgICAgICAgIHRheCA9IHBzX3NwZWNpZXNfcmEgJT4lIGdldF90YXgoKQ0KICAgICAgICAgICAgICByZWxhdGl2ZV9jb3VudHMgJT4lIA0KICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcigtZmVhdHVyZV9pZCwgbmFtZXNfdG8gPSAnU2FtcGxlSUQnLCB2YWx1ZXNfdG8gPSAnY291bnRzJykgJT4lDQogICAgICAgICAgICAgICAgbGVmdF9qb2luKG1ldGFkYXRhLCBieT0nU2FtcGxlSUQnKSAlPiUNCiAgICAgICAgICAgICAgICBsZWZ0X2pvaW4odGF4LCBieT0nZmVhdHVyZV9pZCcpICU+JQ0KICAgICAgICAgICAgICAgIGdyb3VwX2J5KFNwZWNpZXMpICU+JQ0KICAgICAgICAgICAgICAgIG11dGF0ZShwcmV2YWxlbmNlX2VudGlyZV9kYXRhc2V0ID0gc3VtKGNvdW50cyA+IDApIC8gbigpLA0KICAgICAgICAgICAgICAgICAgICAgICBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCA9IG1lYW4oY291bnRzKSkgJT4lDQogICAgICAgICAgICAgICAgZ3JvdXBfYnkoU3BlY2llcywgQ29ybl9HZW5vdHlwZSkgJT4lDQogICAgICAgICAgICAgICAgc3VtbWFyaXplKHByZXZhbGVuY2UgPSBzdW0oY291bnRzID4gMCkgLyBuKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlID0gbWVhbihjb3VudHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2YWxlbmNlX2VudGlyZV9kYXRhc2V0ID0gZmlyc3QocHJldmFsZW5jZV9lbnRpcmVfZGF0YXNldCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0ID0gZmlyc3QobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQpKSAlPiUNCiAgICAgICAgICAgICAgICB1bmdyb3VwKCl9KQ0KcHJldl9jb3JuX3NwZWNpZXMkYDE2U2AgJT4lIA0KICByZW5hbWUodG90YWwgPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCkgJT4lDQogIGRpc3RpbmN0KFNwZWNpZXMsIENvcm5fR2Vub3R5cGUsIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCB0b3RhbCkgJT4lDQogIG11dGF0ZShtZWFuX3JlbGF0aXZlX2FidW5kYW5jZT0gcm91bmQobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIDMpLA0KICAgICAgICAgdG90YWwgPSByb3VuZCh0b3RhbCwgMykpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ29ybl9HZW5vdHlwZSwgdmFsdWVzX2Zyb20gPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSkgJT4lDQogIGZpbHRlcih0b3RhbCA+PSAwLjAxKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lDQogIGtibChmb3JtYXQgPSAnaHRtbCcsIGNvbC5uYW1lcyA9IGMoJ1NwZWNpZXMnLCAnVG90YWwgUmVsYXRpdmUgQWJ1bmRhbmNlJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JlbGF0aXZlIGFidW5kYW5jZSBCNzMnLCAnUmVsYXRpdmUgYWJ1bmRhbmNlIENNTDMyMicpKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIlRpbWVzIE5ldyBSb21hbiIpDQpwcmV2X2Nvcm5fc3BlY2llcyRJVFMgJT4lIA0KICByZW5hbWUodG90YWwgPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCkgJT4lDQogIGRpc3RpbmN0KFNwZWNpZXMsIENvcm5fR2Vub3R5cGUsIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCB0b3RhbCkgJT4lDQogIG11dGF0ZShtZWFuX3JlbGF0aXZlX2FidW5kYW5jZT0gcm91bmQobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIDMpLA0KICAgICAgICAgdG90YWwgPSByb3VuZCh0b3RhbCwgMykpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ29ybl9HZW5vdHlwZSwgdmFsdWVzX2Zyb20gPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSkgJT4lDQogIGZpbHRlcih0b3RhbCA+PSAwLjAxKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lDQogIGtibChmb3JtYXQgPSAnaHRtbCcsIGNvbC5uYW1lcyA9IGMoJ1NwZWNpZXMnLCAnVG90YWwgUmVsYXRpdmUgQWJ1bmRhbmNlJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JlbGF0aXZlIGFidW5kYW5jZSBCNzMnLCAnUmVsYXRpdmUgYWJ1bmRhbmNlIENNTDMyMicpKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIlRpbWVzIE5ldyBSb21hbiIpDQpgYGANCg0KDQpCZWxvdyBhcmUgYmFycGxvdHMgb2YgcmVsYXRpdmUgdGF4b24gYWJ1bmRhbmNlcyBmb3IgMTZTIHNlcXVlbmNpbmcgd2l0aCBzYW1wbGVzIGdyb3VwZWQgYWNjb3JkaW5nIHRvIHNpbWlsYXJpdHkgdXNpbmcgdGhlIG5lYXRtYXAgbWV0aG9kLiANCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMCwgd2FybmluZz1GQUxTRSwgZmlnLnNob3c9J2hpZGUnfQ0KIyMgaHR0cHM6Ly9naXRodWIuY29tL2dvb2dsZS9wYWxldHRlLmpzL2Jsb2IvNzlhNzAzZGYzNDRlM2IyNDM4MGNlMWEyMTFhMmRmN2YyZDkwY2EyMi9wYWxldHRlLmpzI0w4MDINCm1wbjY1ID0gYygnI2ZmMDAyOScsJyMzNzdlYjgnLCcjNjZhNjFlJywnIzk4NGVhMycsJyMwMGQyZDUnLCcjZmY3ZjAwJywnI2FmOGQwMCcsJyM3ZjgwY2QnLCcjYjNlOTAwJywnI2M0MmU2MCcsJyNhNjU2MjgnLA0KICAgICAgICAgJyNmNzgxYmYnLCcjOGRkM2M3JywnI2JlYmFkYScsJyNmYjgwNzInLCcjODBiMWQzJywnI2ZkYjQ2MicsJyNmY2NkZTUnLCcjYmM4MGJkJywnI2ZmZWQ2ZicsJyNjNGVhZmYnLCcjY2Y4YzAwJywNCiAgICAgICAgICcjMWI5ZTc3JywnI2Q5NWYwMicsJyNlNzI5OGEnLCcjZTZhYjAyJywnI2E2NzYxZCcsJyMwMDk3ZmYnLCcjMDBkMDY3JywnIzAwMDAwMCcsJyMyNTI1MjUnLCcjNTI1MjUyJywnIzczNzM3MycsDQogICAgICAgICAnIzk2OTY5NicsJyNiZGJkYmQnLCcjZjQzNjAwJywnIzRiYTkzYicsJyM1Nzc5YmInLCcjOTI3YWNjJywnIzk3ZWUzZicsJyNiZjM5NDcnLCcjOWY1YjAwJywnI2Y0ODc1OCcsJyM4Y2FlZDYnLA0KICAgICAgICAgJyNmMmI5NGYnLCcjZWZmMjZlJywnI2U0Mzg3MicsJyNkOWIxMDAnLCcjOWQ3YTAwJywnIzY5OGNmZicsJyNkOWQ5ZDknLCcjMDBkMjdlJywnI2QwNjgwMCcsJyMwMDlmODInLCcjYzQ5MjAwJywNCiAgICAgICAgICcjY2JlOGZmJywnI2ZlY2RkZicsJyNjMjdlYjYnLCcjOGNkMmNlJywnI2M0YjhkOScsJyNmODgzYjAnLCcjYTQ5MTAwJywnI2Y0ODgwMCcsJyMyN2QwZGYnLCcjYTA0YTliJykNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTh9DQptYXAocmFua19uYW1lcyhwc19nZW51cyRgMTZTYClbMjo2XSwgZnVuY3Rpb24odGF4X3Jhbmspew0KICBkZiA9IHBzX2dlbnVzJGAxNlNgICU+JSANCiAgICBzcGVlZHlzZXE6Om11dGF0ZV9zYW1wbGVfZGF0YShjb25kaXRpb24gPSBjb25kaXRpb25fd19yZXApICU+JQ0KICAgIHRyYW5zZm9ybSh0cmFuc2Zvcm0gPSAiY29tcG9zaXRpb25hbCIpICU+JQ0KICAgIGFnZ3JlZ2F0ZV9yYXJlKGxldmVsID0gdGF4X3JhbmssIGRldGVjdGlvbiA9IDAuMDUsIHByZXZhbGVuY2UgPSAwLjA1KSANCiAgcCA9IHBsb3RfY29tcG9zaXRpb24oZGYsIHgubGFiZWw9J2NvbmRpdGlvbicsIG90dS5zb3J0ID0gJ2FidW5kYW5jZScsIHNhbXBsZS5zb3J0PSduZWF0bWFwJykgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChuY29sID0gMSkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPW1wbjY1KSArDQogIHRoZW1lX21pbmltYWwoKSArIA0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MCwgdmp1c3Q9MC41KSkgKw0KICBsYWJzKHggPSAiU2FtcGxlIGNvbmRpdGlvbiIsDQogICAgICAgeSA9ICJSZWxhdGl2ZSBhYnVuZGFuY2UiLA0KICAgICAgIHRpdGxlID0gZ2x1ZSgiMTZTIFJlbGF0aXZlIGFidW5kYW5jZSBhdCB7dGF4X3Jhbmt9IGxldmVsIiksIA0KICAgICAgIGZpbGwgPSB0YXhfcmFuaykNCiAgICAgcCAlPiUgcGxvdGx5OjpnZ3Bsb3RseSgpDQp9KQ0KYGBgDQoNCg0KPGJyPjxicj48YnI+PGJyPjxicj48YnI+IFRoZSBuZXh0IHR3byBzZXRzIGFyZSBkb25lIHdpdGggSVRTIGNvdW50cyBidXQgbWFkZSB0aGUgc2FtZSB3YXkgYXMgYWJvdmUuDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0NCm1hcChyYW5rX25hbWVzKHBzX2dlbnVzJElUUylbMjo2XSwgZnVuY3Rpb24odGF4X3Jhbmspew0KICBkZiA9IHBzX2dlbnVzJElUUyAlPiUgDQogICAgc3BlZWR5c2VxOjptdXRhdGVfc2FtcGxlX2RhdGEoY29uZGl0aW9uID0gY29uZGl0aW9uX3dfcmVwKSAlPiUNCiAgICB0cmFuc2Zvcm0odHJhbnNmb3JtID0gImNvbXBvc2l0aW9uYWwiKSAlPiUNCiAgICBhZ2dyZWdhdGVfcmFyZShsZXZlbCA9IHRheF9yYW5rLCBkZXRlY3Rpb24gPSAwLjA1LCBwcmV2YWxlbmNlID0gMC4wNSkgDQogIHAgPSBwbG90X2NvbXBvc2l0aW9uKGRmLCB4LmxhYmVsPSdjb25kaXRpb24nLCBvdHUuc29ydCA9ICdhYnVuZGFuY2UnLCBzYW1wbGUuc29ydD0nbmVhdG1hcCcpICsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobmNvbCA9IDEpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1tcG42NSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKyANCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTkwLGhqdXN0PTAsIHZqdXN0PTAuNSkpICsNCiAgbGFicyh4ID0gIlNhbXBsZSBjb25kaXRpb24iLA0KICAgICAgIHkgPSAiUmVsYXRpdmUgYWJ1bmRhbmNlIiwNCiAgICAgICB0aXRsZSA9IGdsdWUoIklUUyBSZWxhdGl2ZSBhYnVuZGFuY2UgYXQge3RheF9yYW5rfSBsZXZlbCIpLCANCiAgICAgICBmaWxsID0gdGF4X3JhbmspDQogIHAgJT4lIHBsb3RseTo6Z2dwbG90bHkoKQ0KfSkNCmBgYA0KDQoNCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9OCwgd2FybmluZz1GQUxTRX0NCnBydW5lX3RheGEobmFtZXMoc29ydCh0YXhhX3N1bXMocHNfZ2VudXNfcmEkYDE2U2ApLGRlY3JlYXNpbmcgPSBUUlVFKVsxOjMwXSksIHBzX2dlbnVzX3JhJGAxNlNgKSAlPiUNCiAgc3BlZWR5c2VxOjpwbG90X2hlYXRtYXAobWV0aG9kID0gIk5NRFMiLCBkaXN0YW5jZSA9ICJicmF5Iiwgc2FtcGxlLmxhYmVsID0gJ2NvbmRpdGlvbicsIHRheGEubGFiZWw9J0dlbnVzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MCwgdmp1c3Q9MC41LCBzaXplID0gMTApLA0KICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSkgKw0KICBsYWJzKHRpdGxlID0gJzE2UyBIZWF0bWFwIG9mIHRvcCAzMCBtb3N0IGFidW5kYW50IGdlbmVyYScpDQpgYGANCg0KPGJyPjxicj48YnI+PGJyPjxicj48YnI+DQoNCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9OCwgd2FybmluZz1GQUxTRX0NCnBydW5lX3RheGEobmFtZXMoc29ydCh0YXhhX3N1bXMocHNfZ2VudXNfcmEkSVRTKSxkZWNyZWFzaW5nID0gVFJVRSlbMTozMF0pLCBwc19nZW51c19yYSRJVFMpICU+JQ0KICBzcGVlZHlzZXE6OnBsb3RfaGVhdG1hcChtZXRob2QgPSAiTk1EUyIsIGRpc3RhbmNlID0gImJyYXkiLCBzYW1wbGUubGFiZWwgPSAnY29uZGl0aW9uJywgdGF4YS5sYWJlbD0nR2VudXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0wLCB2anVzdD0wLjUsIHNpemUgPSAxMCksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjIpKSArDQogIGxhYnModGl0bGUgPSAnSVRTIEhlYXRtYXAgb2YgdG9wIDMwIG1vc3QgYWJ1bmRhbnQgZ2VuZXJhJykNCmBgYA0KYGBge3J9DQpzYXZlLmltYWdlKGhlcmUoJ3NyYy8xNl9hbmRfSVRTX2ltcG9ydC5SRGF0YScpKQ0KYGBgDQoNCg==